package edu.cs.usask.ca.silver.businesslogic.commands.generic;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.UUID;

import edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI;
import edu.cs.usask.ca.silver.api.persistence.StorageI;
import edu.cs.usask.ca.silver.businesslogic.ids.FileID;
import edu.cs.usask.ca.silver.businesslogic.ids.GroupID;
import edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID;
import edu.cs.usask.ca.silver.businesslogic.ids.ModelVersionID;
import edu.cs.usask.ca.silver.businesslogic.util.SilverAutoManagedObjectFactory;
import edu.cs.usask.ca.silver.businesslogic.util.SilverBLTransactionManager;
import edu.cs.usask.ca.silver.definitions.SupportedModelType;
import edu.cs.usask.ca.silver.definitions.SystemProperties;

public class ModelProject implements ModelProjectI {

	private static final SilverAutoManagedObjectFactory mpFactory = new SilverAutoManagedObjectFactory(
			"edu.cs.usask.ca.silver.businesslogic.commands.generic.ModelProject");

	private static final String baseline = "baseline";

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#
	 * createModelProjectWithSource(java.lang.String, java.lang.String,
	 * java.lang.String, java.lang.String)
	 */
	public ModelProjectID createGenericModelProjectWithSource(
			GroupID parentGroup, String mpName, String mpCreator,
			String mpDescr, String sourceFileLocation, StorageI storage)
			throws Exception {

		ModelProjectID mpId;
		boolean error = false;

		try {
			SilverBLTransactionManager.startTransaction();
			mpId = createGenericModelProject(parentGroup, mpName, mpCreator,
					mpDescr, null, storage);
			ModelVersion _modelVersion = new ModelVersion();

			_modelVersion.createGenericModelVersionFromLocalInputFile(
					SystemProperties.BASELINE_MV, mpCreator,
					SystemProperties.DEFAULT_DESCRIPTION, mpId,
					sourceFileLocation, SystemProperties.IS_VISIBLE, storage);
		} catch (Exception e) {
			error = true;
			throw e;
		} finally {
			try {
				SilverBLTransactionManager.closeTransaction(error);
			} catch (Exception e) {
				throw e;
			}
		}
		return mpId;
	}

	@Override
	public ModelProjectID createAnylogicProjectWithSource(GroupID parentGroup,
			String mpName, String mpCreator, String mpDescr, String sourceFile,
			String classFile, StorageI storage) throws Exception {

		ModelProjectID mpId;
		boolean error = false;

		try {
			SilverBLTransactionManager.startTransaction();
			mpId = createAnylogicProject(parentGroup, mpName, mpCreator,
					mpDescr, null, null, storage);
			ModelVersion _modelVersion = new ModelVersion();

			_modelVersion.createAnylogicModelVersionFromLocalInputFile(
					SystemProperties.BASELINE_MV, mpCreator,
					SystemProperties.BASELINE_MV, mpId, sourceFile, classFile,
					SystemProperties.IS_VISIBLE, storage);
		} catch (Exception e) {
			error = true;
			throw e;
		} finally {
			try {
				SilverBLTransactionManager.closeTransaction(error);
			} catch (Exception e) {
				throw e;
			}
		}
		return mpId;
	}

	@Override
	public ModelProjectID createVensimModelProjectWithSource(
			GroupID parentGroup, String mpName, String mpCreator,
			String mpDescr, String soureFileLocation, StorageI storage)
			throws Exception, UnsatisfiedLinkError {
		ModelProjectID mpId;
		boolean error = false;

		try {
			SilverBLTransactionManager.startTransaction();
			mpId = createVensimModelProject(parentGroup, mpName, mpCreator,
					mpDescr, null, storage);
			ModelVersion _modelVersion = new ModelVersion();

			_modelVersion.createVensimModelVersionFromLocalInputFile(
					SystemProperties.BASELINE_MV, mpCreator,
					SystemProperties.DEFAULT_DESCRIPTION, mpId,
					soureFileLocation, SystemProperties.IS_VISIBLE, storage);
		} catch (java.lang.UnsatisfiedLinkError e1) {
			error = true;
			throw e1;
		} catch (Exception e) {
			error = true;
			throw e;
		} finally {
			try {
				SilverBLTransactionManager.closeTransaction(error);
			} catch (Exception e) {
				throw e;
			}
		}
		return mpId;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#createModelProject
	 * (java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public ModelProjectID createGenericModelProject(GroupID parentGroup,
			String mpName, String mpCreator, String mpDescr, String source,
			StorageI storage) throws Exception {
		UUID temp = storage.addModelProject(parentGroup.getUUIdVal(), mpName,
				mpCreator, SupportedModelType.GENERIC.toString(), mpDescr);
		ModelProjectID mpId = new ModelProjectID(temp);
		return mpId;
	}

	@Override
	public ModelProjectID createModelProject(
			SupportedModelType supportedModelType, GroupID parentGroup,
			String mpName, String mpCreator, String mpDescr, String sourceFile,
			String classFile, StorageI storage) throws Exception {
		switch (supportedModelType) {

		case VENSIM:
			return createVensimModelProject(parentGroup, mpName, mpCreator,
					mpDescr, sourceFile, storage);

		case ANYLOGIC:
			return createAnylogicProject(parentGroup, mpName, mpCreator,
					mpDescr, sourceFile, classFile, storage);

		case GENERIC:
			return createGenericModelProject(parentGroup, mpName, mpCreator,
					mpDescr, sourceFile, storage);

		case UNSPECIFIED:
		default:
			return createGenericModelProject(parentGroup, mpName, mpCreator,
					mpDescr, sourceFile, storage);
		}
	}

	@Override
	public ModelProjectID createVensimModelProject(GroupID parentGroup,
			String mpName, String mpCreator, String mpDescr, String source,
			StorageI storage) throws Exception {

		if (source != null)
			return createVensimModelProjectWithSource(parentGroup, mpName,
					mpCreator, mpDescr, source, storage);

		UUID temp;
		temp = storage.addModelProject(parentGroup.getUUIdVal(), mpName,
				mpCreator, SupportedModelType.VENSIM.toString(), mpDescr);
		return new ModelProjectID(temp);
	}

	@Override
	public ModelProjectID createAnylogicProject(GroupID parentGroup,
			String mpName, String mpCreator, String mpDescr, String sourceFile,
			String classFile, StorageI storage) throws Exception {

		if (sourceFile != null && classFile != null)
			return createAnylogicProjectWithSource(parentGroup, mpName,
					mpCreator, mpDescr, sourceFile, classFile, storage);

		UUID temp;
		temp = storage.addModelProject(parentGroup.getUUIdVal(), mpName,
				mpCreator, SupportedModelType.ANYLOGIC.name(), mpDescr);
		return new ModelProjectID(temp);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getAllModelProjectIDs
	 * ()
	 */
	public ModelProjectID[] getAllModelProjectIDs(StorageI storage)
			throws Exception {
		ArrayList<UUID> result;
		result = storage.getAllModelProjectIDs();
		ModelProjectID[] ids = new ModelProjectID[result.size()];

		int i = 0;
		Iterator<UUID> e = result.iterator();
		while (e.hasNext()) {
			ids[i++] = new ModelProjectID(e.next());
		}
		return ids;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#
	 * getModelProjectNamesByGroupID
	 * (edu.cs.usask.ca.silver.businesslogic.ids.GroupID)
	 */
	public String[] getModelProjectNamesByGroupID(GroupID gId, StorageI storage)
			throws Exception {
		return storage.getModelProjectNamesByGroupId(gId.getUUIdVal());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getModelProjectAsXML
	 * (edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public String getModelProjectAsXML(ModelProjectID mpId, StorageI storage)
			throws Exception {
		String result = storage.getModelProjectAsXML(mpId.getUUIdVal());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getName(edu.cs
	 * .usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public String getName(ModelProjectID mpId, StorageI storage)
			throws Exception {
		String result = storage.getMpName(mpId.getUUIdVal());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getType(edu.cs
	 * .usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public String getType(ModelProjectID mpId, StorageI storage)
			throws Exception {
		return storage.getMpType(mpId.getUUIdVal());
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getParentGroupID
	 * (edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public GroupID getParentGroupID(ModelProjectID mpId, StorageI storage)
			throws Exception {
		return new GroupID(storage.getMpParentGroup(mpId.getUUIdVal()));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getDescription
	 * (edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public String getDescription(ModelProjectID mpId, StorageI storage)
			throws Exception {
		String result = storage.getMpDescription(mpId.getUUIdVal());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getCreator(edu
	 * .cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public String getCreator(ModelProjectID mpId, StorageI storage)
			throws Exception {
		String result = storage.getMpCreator(mpId.getUUIdVal());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getCreationDate
	 * (edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public Date getCreationDate(ModelProjectID mpId, StorageI storage)
			throws Exception {
		Date result = storage.getMpCreationDate(mpId.getUUIdVal());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getCreationTime
	 * (edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public Date getCreationTime(ModelProjectID mpId, StorageI storage)
			throws Exception {
		Date result = storage.getMpCreationTime(mpId.getUUIdVal());
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getModelVersionIds
	 * (edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public ModelVersionID[] getModelVersionIds(ModelProjectID mpId,
			StorageI storage) throws Exception {
		ArrayList<UUID> result;

		result = storage.getMpModelVersionIds(mpId.getUUIdVal());
		ModelVersionID[] ids = new ModelVersionID[result.size()];

		int i = 0;
		Iterator<UUID> e = result.iterator();
		while (e.hasNext()) {
			ids[i++] = new ModelVersionID(e.next());
		}

		return ids;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#getAssociatedFileIds
	 * (edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public FileID[] getAssociatedFileIds(ModelProjectID mpId, StorageI storage)
			throws Exception {
		ArrayList<UUID> result;

		result = storage.getModelProjectAssociatedFileIds(mpId.getUUIdVal());
		FileID[] ids = new FileID[result.size()];

		int i = 0;
		Iterator<UUID> e = result.iterator();
		while (e.hasNext()) {
			ids[i++] = new FileID(e.next());
		}
		return ids;
	}

	/**
	 * not implemented
	 */
	public HashMap<ModelVersionID, String> getModelVersions(
			ModelProjectID mpId, StorageI storage) throws Exception {

		storage.getMpModelVersions(mpId.getUUIdVal());
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#setName(edu.cs
	 * .usask.ca.silver.businesslogic.ids.ModelProjectID, java.lang.String)
	 */
	public boolean setName(ModelProjectID mpId, String name, StorageI storage)
			throws Exception {
		return storage.setMpName(mpId.getUUIdVal(), name);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#setType(edu.cs
	 * .usask.ca.silver.businesslogic.ids.ModelProjectID, java.lang.String)
	 */
	public void setType(ModelProjectID mpId, String type, StorageI storage)
			throws Exception {
		storage.setMpType(mpId.getUUIdVal(), type);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#setDescription
	 * (edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID,
	 * java.lang.String)
	 */
	public boolean setDescription(ModelProjectID mpId, String description,
			StorageI storage) throws Exception {
		return storage.setMpDescription(mpId.getUUIdVal(), description);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.cs.usask.ca.silver.api.businesslogic.ModelProjectI#deleteProject(
	 * edu.cs.usask.ca.silver.businesslogic.ids.ModelProjectID)
	 */
	public boolean deleteProject(ModelProjectID mpId, StorageI storage)
			throws Exception {
		return storage.deleteModelProject(mpId.getUUIdVal());
	}

	public static SilverAutoManagedObjectFactory getObjectPoolFactory() {
		return mpFactory;
	}

}
